/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       town.h

	$Header: /game/town.h $

	$NoKeywords: $

 ************************************************************************/

#ifndef TOWN_H_INCLUDED
#define TOWN_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "abstract_town.h"
#include "army_ptr.h"
#include "hero.h"
#include "owned_adv_object.h"
#include "owned_ptr.h"
#include "spell_set.h"
#include "skill.h"
#include "town_type.h"

class t_ai_town_data_cache;
class t_army_array;
enum  t_terrain_type;
enum  t_combat_result;

extern t_spell_set const k_town_default_required_spells;
extern t_spell_set const k_town_default_potential_spells;

struct t_guild_spell
{
	t_spell spell;
	bool    available;
};

struct t_town_prisoner
{
	t_hero_ptr  hero;
	int         owner_number;
};

typedef std::vector<t_town_building>	t_building_array;
typedef std::vector<t_guild_spell>		t_guild_spell_list;
typedef std::vector<t_town_prisoner>	t_prisoner_list;

// ---------------------------------------------------------------
// town adventure object
// ---------------------------------------------------------------

class t_town : public t_abstract_town
{
public:
	enum { k_population_divisor = 700 }; // m_population & get_growth() is divided by this to get whole creatures

	t_town();
	explicit t_town( t_abstract_town* source );
	t_town( std::string const& source, t_qualified_adv_object_type const& type );
	virtual ~t_town();

	virtual void				activate_trigger( t_army* army, t_adv_map_point const& point, 
										          t_direction direction,
												  t_adventure_frame* frame );
	bool						adjust_population(int dwelling, int amount);
	void						add_prisoner( t_town_prisoner * prisoner );
	float						ai_value( bool demand_scaling = false ) const;
	virtual float				ai_value( t_adventure_ai const& ai, t_creature_array const& army, int move_cost ) const;	
	virtual float				ai_activation_value_drop( t_creature_array const& army ) const;
	void						apply_building_delay();
	void						army_attacks_town( t_army* army, t_adv_map_point const& point, t_adv_map_point const& source_point,
												   t_adventure_frame* adventure_frame, t_combat_result & combat_result );
	void						army_visits_town( t_army * army, t_adventure_frame* adventure_frame, bool skip_town_screen = false );
	bool						build_ship() const;
	void						buy_building( t_town_building ); // create & pay for building
    bool                        can_afford( t_town_building building ) const;
	bool						can_build( t_town_building ) const;
	bool						can_buy( t_town_building ) const;
	void						check_bonus_buildings( t_army *adjacent_army, t_window *frame, bool check_garrison = true ); // Temporary & one-time bonuses
	void						create_building( t_town_building building );  // create
	void						create_spells( t_spell_set const &	required_spells,
											   t_spell_set const &  potential_spells,
											   t_adventure_map&		map );
	virtual void				destroy();
	void						disallow_might_mage_guilds();
	void						display_growth_breakdown_window( t_town_building building, t_window *parent );
	void						display_growth_breakdown_window( t_creature_type creature, t_window *parent );
	bool						find_new_ship_position( t_adv_map_point & result, 
		                                                bool ignore_removable ) const;
	void						free_prisoners();
    t_army_array*               get_adjacent_armies();
	t_ai_town_data_cache*		get_ai_town_data_cache() const;
	virtual t_skill_mastery		get_anti_stealth_level() const;
	t_bitmap_cursor const&	    get_cursor( t_adventure_map_window const& window,
		                                    t_army const* army ) const;
	int							get_gold_production() const;
	int							get_growth( t_town_building building ) const;
	int							get_growth( t_creature_type creature ) const;
	int							get_last_treasury_bonus() const;
	t_army_ptr					get_last_visiting_army() const;
	t_town_type                 get_library_type( t_town_building building ) const;
	t_uint8						get_mana_vortex_delay() const;
	int						    get_population( t_creature_type creature );
	int						    get_population( int dwelling ) const;
	int							get_portal_charge() const;
	t_creature_type				get_portal_creature() const;
	int							get_portal_population() const;
    t_prisoner_list &           get_prisoner_list();
	std::string				    get_requirements_text( t_town_building building ) const;
	t_skill_list const&		    get_school_skills() const;
	t_guild_spell_list const&	get_spells() const;
	int							get_tavern_delay() const;
	t_terrain_type				get_terrain() const;
	t_town*						get_town();
	virtual int					get_version() const;
	virtual bool				get_virtual_position( t_adv_map_point& position ) const;
	bool						has_built() const;
	int							hire_creatures( t_creature_type creature, int amount );
	void						init(); // Used by the constructors to init. props. to default values.
	virtual void                initialize( t_adventure_map& map );
	bool						is_enabled( t_town_building, bool check_requirements = true ) const;
	virtual bool				is_triggered_by( t_creature_array const& army ) const;
	virtual void				left_double_click( t_mouse_event const& event, 
										           t_adventure_frame* frame );
	virtual void				on_begin_turn();
	virtual void				on_combat_end( t_army* attacker, t_combat_result result,
											   t_creature_array* losses, t_adventure_frame* frame );
	virtual void				on_end_turn();
	virtual void				pathing_destination_query( t_adventure_path_point const& source, 
														   t_adventure_path_finder & path_finder ) const;
	virtual void				place( t_adventure_map& map, t_adv_map_point const& point );
	virtual bool				preplacement( t_adventure_map& map, int pass );
	virtual void				preprocess_new_day();
	virtual bool				process_continuous_events( t_adventure_map& map );
	virtual void				process_new_day();
	virtual bool				process_timed_events( t_adventure_map& map, bool start_of_day = true );
	virtual bool				process_triggerable_events( t_adventure_map& map, std::string const& name );
	virtual bool                read( std::streambuf&						stream, 
									  t_qualified_adv_object_type const&	type,
									  int									version );
	virtual void				read_postplacement( t_adventure_map& map );
	virtual bool				read_from_map( std::streambuf& buffer, t_progress_handler* );
	virtual void				right_click( t_mouse_event const& event, t_adventure_frame* adventure_frame );
	virtual bool				select();
	virtual void				set_owner( int player_number );
	void						set_portal_creature( t_creature_type creature );
	void						set_start_buildings();
	void						set_start_creatures();
	void						set_start_population();
	void						set_tavern_delay( int arg );
	void						set_visiting_army( t_army_ptr army );
	void						setup_school_skills( t_skill_set local_available_skills, t_skill_set local_required_skills, t_skill_set global_allowed_skills );
	virtual void				update_state();
	int							use_portal( int amount );
	void						use_up_mana_vortex();
	virtual bool				write( std::streambuf& stream ) const;	

protected:
	typedef	t_owned_ptr< t_ai_town_data_cache > t_ai_town_data_cache_ptr;

	// Data read in by read_from_map and used by initialize
	struct t_temp_read_from_map_data;

	void captured( t_army* army, t_adventure_frame* frame );
	int	 create_creatures( t_creature_type creature, int amount );
	void execute_script(t_built_in_event_id event_id, t_army* army);
	void kill_arrived_caravans( t_army * victorious_army );
	void neutral_growth();
	void set_terrain();
	bool update_model();
	void update_spells();
	void visit_booster( bool check_garrison, t_army *adjacent_army, t_town_building building, t_window* frame );
	void visit_single_use( bool check_garrison, t_army *adjacent_army, int single_use_id, t_town_building building, t_window* frame );
	void warn_of_approaching_caravans();

	// The "town" part of m_ai_town_data_cache_ptr may seem redundant.  It's necessary... towns are derived
	// from creature_array, and creature_array is already using m_ai_data_cache_ptr for it's cache,
	t_ai_town_data_cache_ptr	m_ai_town_data_cache_ptr; 
	t_uint8						m_building_delay; // Number of days until we can build another structure
	t_army_ptr					m_last_visiting_army;
	t_uint32					m_last_treasury_bonus; // Amount of gold the treasury gave us today times 256.
	t_uint8						m_mana_vortex_delay;
	int							m_population[k_dwelling_count]; // note: population is stored as 1/700th fractions ( 1 / k_population_divisor )
	int							m_portal_charge;
	t_creature_type				m_portal_creature;
	t_prisoner_list				m_prisoner_list;
	int							m_single_use_id; // For Arena of Honor, Battle Academy, and Sacred Grove
	t_guild_spell_list			m_spells;
	t_skill_list				m_school_skills;
	int							m_tavern_delay;
	t_owned_ptr< t_temp_read_from_map_data > m_temp_read_from_map_data; // Valid only between read_from_map() and initialize()
	t_terrain_type				m_terrain;
 	int							m_training_grounds_use_id; // For Thief's Gauntlet and Wrestling Pits
};

inline t_army_ptr t_town::get_last_visiting_army() const
{
	return m_last_visiting_army;
}

inline int t_town::get_last_treasury_bonus() const
{
	// In actual gold pieces, not fractional
	return m_last_treasury_bonus >> 8;
}

inline t_uint8 t_town::get_mana_vortex_delay() const
{
	return m_mana_vortex_delay;
}

inline int t_town::get_portal_charge() const
{
	return m_portal_charge;
}

inline t_creature_type t_town::get_portal_creature() const
{
	return m_portal_creature;
}

inline t_skill_list const& t_town::get_school_skills() const
{
	return m_school_skills;
}

inline t_guild_spell_list const& t_town::get_spells() const
{
	return m_spells;
}

inline int t_town::get_tavern_delay() const
{
	return m_tavern_delay;
}

inline t_terrain_type t_town::get_terrain() const
{
	return m_terrain;
}

inline t_prisoner_list & t_town::get_prisoner_list()
{
	return m_prisoner_list;
}

inline void t_town::set_visiting_army( t_army_ptr army )
{
	m_last_visiting_army = army;
}

inline void t_town::set_portal_creature( t_creature_type creature )
{
	m_portal_creature = creature;
}

inline void t_town::set_tavern_delay( int arg )
{
	m_tavern_delay = arg;
}

// ---------------------------------------------------------------
// outpost adventure object
// ---------------------------------------------------------------

class t_outpost : public t_owned_adv_object
{
public:
	t_outpost( std::string const& model_name );

	virtual int	 get_version() const;
	virtual bool read_from_map( std::streambuf& buffer, t_progress_handler* );
	virtual bool read( std::streambuf&						stream, 
				       t_qualified_adv_object_type const&	type,
				       int									version );
};

inline t_outpost::t_outpost( std::string const& model_name )
	:	t_owned_adv_object( model_name )
{
}

// ---------------------------------------------------------------
// ---------------------------------------------------------------

void ai_distribute_value_to_requirements( t_town* town, t_town_building building, float const* raw_values, float* values );

int const k_town_tavern_delay = 7;

#endif

